﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Framework.Core.Extensions;

namespace Framework.AspNetCore.UnifyResult.Fiters
{
	/// <summary>
	/// 友好异常拦截器
	/// </summary>
	public sealed class FriendlyExceptionFilter : IAsyncExceptionFilter
	{
		/// <summary>
		/// 异常拦截
		/// </summary>
		/// <param name="context"></param>
		/// <returns></returns>
		public async Task OnExceptionAsync(ExceptionContext context)
		{

			// 排除 WebSocket 请求处理
			if (context.HttpContext.IsWebSocketRequest()) return;

			// 如果异常在其他地方被标记了处理，那么这里不再处理
			if (context.ExceptionHandled) return;

			// 解析异常信息
			var exceptionMetadata = GetExceptionMetadata(context);

			IUnifyResultProvider unifyResult = context.GetRequiredService<IUnifyResultProvider>();
			// 执行规范化异常处理
			context.Result = unifyResult.OnException(context, exceptionMetadata);

			// 创建日志记录器
			var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<FriendlyExceptionFilter>>();

			// 记录拦截日常
			logger.LogError(context.Exception, context.Exception.Message);
		}

		/// <summary>
		/// 获取异常元数据
		/// </summary>
		/// <param name="context"></param>
		/// <returns></returns>
		public static ExceptionMetadata GetExceptionMetadata(ActionContext context)
		{
			object errorCode = default;
			object originErrorCode = default;
			object errors = default;
			object data = default;
			var statusCode = StatusCodes.Status500InternalServerError;
			var isValidationException = false; // 判断是否是验证异常
			var isFriendlyException = false;

			// 判断是否是 ExceptionContext 或者 ActionExecutedContext
			var exception = context is ExceptionContext exContext
				? exContext.Exception
				: (
					context is ActionExecutedContext edContext
						? edContext.Exception
						: default
				);

			// 判断是否是友好异常
			if (exception is UserFriendlyException friendlyException)
			{
				int statusCode2 = 500;
				int.TryParse(friendlyException.Code, out statusCode2);
				isFriendlyException = true;
				errorCode = friendlyException.Code;
				originErrorCode = friendlyException.Code;
				statusCode = statusCode2 == 0 ? 403 : statusCode2;
				isValidationException = false;
				errors = friendlyException.Message;
				data = friendlyException.Data;
			}

			return new ExceptionMetadata
			{
				StatusCode = statusCode,
				ErrorCode = errorCode,
				OriginErrorCode = originErrorCode,
				Errors = errors,
				Data = data
			};
		}
	}
}
